const isWeex = typeof WXEnvironment !== 'undefined';
const isWeexIOS = isWeex && /ios/i.test(WXEnvironment.platform);
const isWeexAndroid = isWeex && !isWeexIOS;

import GLmethod from '../context-webgl/GLmethod';

const GCanvasModule =
	(typeof weex !== 'undefined' && weex.requireModule) ? (weex.requireModule('gcanvas')) :
	(typeof __weex_require__ !== 'undefined') ? (__weex_require__('@weex-module/gcanvas')) : {};

let isDebugging = false;

let isComboDisabled = false;

const logCommand = (function() {
	const methodQuery = [];
	Object.keys(GLmethod).forEach(key => {
		methodQuery[GLmethod[key]] = key;
	})
	const queryMethod = (id) => {
		return methodQuery[parseInt(id)] || 'NotFoundMethod';
	}
	const logCommand = (id, cmds) => {
		const mId = cmds.split(',')[0];
		const mName = queryMethod(mId);
		console.log(`=== callNative - componentId:${id}; method: ${mName}; cmds: ${cmds}`);
	}
	return logCommand;
})();

function joinArray(arr, sep) {
	let res = '';
	for (let i = 0; i < arr.length; i++) {
		if (i !== 0) {
			res += sep;
		}
		res += arr[i];
	}
	return res;
}

const commandsCache = {}

const GBridge = {

	callEnable: (ref, configArray) => {

		commandsCache[ref] = [];

		return GCanvasModule.enable({
			componentId: ref,
			config: configArray
		});
	},

	callEnableDebug: () => {
		isDebugging = true;
	},

	callEnableDisableCombo: () => {
		isComboDisabled = true;
	},

	callSetContextType: function(componentId, context_type) {
		GCanvasModule.setContextType(context_type, componentId);
	},

	callReset: function(id) {
		GCanvasModule.resetComponent && canvasModule.resetComponent(componentId);
	},

	render: isWeexIOS ? function(componentId) {
		return GCanvasModule.extendCallNative({
			contextId: componentId,
			type: 0x60000001
		});
	} : function(componentId) {
		return callGCanvasLinkNative(componentId, 0x60000001, 'render');
	},

	render2d: isWeexIOS ? function(componentId, commands, callback) {

		if (isDebugging) {
			console.log('>>> >>> render2d ===');
			console.log('>>> commands: ' + commands);
		}

		GCanvasModule.render([commands, callback ? true : false], componentId, callback);

	} : function(componentId, commands, callback) {

		if (isDebugging) {
			console.log('>>> >>> render2d ===');
			console.log('>>> commands: ' + commands);
		}

		callGCanvasLinkNative(componentId, 0x20000001, commands);
		if (callback) {
			callback();
		}
	},

	callExtendCallNative: isWeexIOS ? function(componentId, cmdArgs) {

		throw 'should not be here anymore ' + cmdArgs;

	} : function(componentId, cmdArgs) {

		throw 'should not be here anymore ' + cmdArgs;

	},


	flushNative: isWeexIOS ? function(componentId) {

		const cmdArgs = joinArray(commandsCache[componentId], ';');
		commandsCache[componentId] = [];

		if (isDebugging) {
			console.log('>>> >>> flush native ===');
			console.log('>>> commands: ' + cmdArgs);
		}

		const result = GCanvasModule.extendCallNative({
			"contextId": componentId,
			"type": 0x60000000,
			"args": cmdArgs
		});

		const res = result && result.result;

		if (isDebugging) {
			console.log('>>> result: ' + res);
		}

		return res;

	} : function(componentId) {

		const cmdArgs = joinArray(commandsCache[componentId], ';');
		commandsCache[componentId] = [];

		if (isDebugging) {
			console.log('>>> >>> flush native ===');
			console.log('>>> commands: ' + cmdArgs);
		}

		const result = callGCanvasLinkNative(componentId, 0x60000000, cmdArgs);

		if (isDebugging) {
			console.log('>>> result: ' + result);
		}

		return result;
	},

	callNative: function(componentId, cmdArgs, cache) {

		if (isDebugging) {
			logCommand(componentId, cmdArgs);
		}

		commandsCache[componentId].push(cmdArgs);

		if (!cache || isComboDisabled) {
			return GBridge.flushNative(componentId);
		} else {
			return undefined;
		}
	},

	texImage2D(componentId, ...args) {
		if (isWeexIOS) {
			if (args.length === 6) {
				const [target, level, internalformat, format, type, image] = args;
				GBridge.callNative(
					componentId,
					GLmethod.texImage2D + ',' + 6 + ',' + target + ',' + level + ',' + internalformat + ',' +
					format + ',' + type + ',' + image.src
				)
			} else if (args.length === 9) {
				const [target, level, internalformat, width, height, border, format, type, image] = args;
				GBridge.callNative(
					componentId,
					GLmethod.texImage2D + ',' + 9 + ',' + target + ',' + level + ',' + internalformat + ',' +
					width + ',' + height + ',' + border + ',' +
					+format + ',' + type + ',' + (image ? image.src : 0)
				)
			}
		} else if (isWeexAndroid) {
			if (args.length === 6) {
				const [target, level, internalformat, format, type, image] = args;
				GCanvasModule.texImage2D(componentId, target, level, internalformat, format, type, image.src);
			} else if (args.length === 9) {
				const [target, level, internalformat, width, height, border, format, type, image] = args;
				GCanvasModule.texImage2D(componentId, target, level, internalformat, width, height, border, format,
					type, (image ? image.src : 0));
			}
		}
	},

	texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image) {
		if (isWeexIOS) {
			if (arguments.length === 8) {
				GBridge.callNative(
					componentId,
					GLmethod.texSubImage2D + ',' + 6 + ',' + target + ',' + level + ',' + xoffset + ',' +
					yoffset, +',' + format + ',' + type + ',' + image.src
				)
			}
		} else if (isWeexAndroid) {
			GCanvasModule.texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image.src);
		}
	},

	bindImageTexture(componentId, src, imageId) {
		GCanvasModule.bindImageTexture([src, imageId], componentId);
	},

	perloadImage([url, id], callback) {
		GCanvasModule.preLoadImage([url, id], function(image) {
			image.url = url;
			image.id = id;
			callback(image);
		});
	},

	measureText(text, fontStyle, componentId) {
		return GCanvasModule.measureText([text, fontStyle], componentId);
	},

	getImageData(componentId, x, y, w, h, callback) {
		GCanvasModule.getImageData([x, y, w, h], componentId, callback);
	},

	putImageData(componentId, data, x, y, w, h, callback) {
		GCanvasModule.putImageData([x, y, w, h, data], componentId, callback);
	},

	toTempFilePath(componentId, x, y, width, height, destWidth, destHeight, fileType, quality, callback) {
		GCanvasModule.toTempFilePath([x, y, width, height, destWidth, destHeight, fileType, quality], componentId,
			callback);
	}
}

export default GBridge;